/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


package fork.modbox;

import fork.Modbox;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import tal.drivechain.chain.Chain;
import tal.drivechain.chain.ChainNode;
import tal.drivechain.chain.ChainNode.MSG;
import tal.drivechain.gui.GUIPopup;
import tal.drivechain.gui.TextButton;
import tal.drivechain.module.properties.ColorParser;
import tal.drivechain.plugin.Channel;
import tal.drivechain.variable.Variable;

/**
 *
 * @author eisental
 */
public abstract class NodePopup extends GUIPopup {

    Modbox owner;

    JLabel classLabel = new JLabel();
    JTextField nameField = new JTextField();
    JLabel sendLabel = new JLabel("type and press enter to send msg:");
    JTextArea msgArea = new JTextArea(3, 20);
    TextButton removeButton, saveChainButton, startStopButton, copyButton, duplicateButton, debugButton, infoButton;
    TextButton disconnectButton;

    public NodePopup(Modbox modbox) {
        super(ColorParser.xor(modbox.getColor()));
        this.owner = modbox;
        this.setLayout(new GridBagLayout());
        

        classLabel.setOpaque(true);
        classLabel.setBackground(Color.BLACK);

        nameField.setOpaque(true);
        nameField.setBackground(Color.BLACK);

        disconnectButton = new TextButton("disconnect >", xor(modbox.getColor()), modbox.getFont());
        disconnectButton.setNegative(true);
        disconnectButton.setHasBorder(false);

        removeButton = new TextButton("remove", xor(modbox.getColor()), modbox.getFont());
        removeButton.setNegative(false);
        removeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                NodePopup.this.setVisible(false);
                NodeCube[] selected = NodePopup.this.owner.getGUI().getGraph().getSelectedCubes().toArray(new NodeCube[0]);
                for (NodeCube n : selected) {
                    n.setSelected(false);
                    n.getChainNode().destroy();
                }

                NodePopup.this.owner.getGUI().getGraph().clearSelection();
            }
        });

        startStopButton = new TextButton("stop", xor(modbox.getColor()), modbox.getFont());
        startStopButton.setToggleButton(true);
        startStopButton.setUnselectedText("start");
        startStopButton.setNegative(false);
        startStopButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                NodePopup.this.setVisible(false);
                for (NodeCube c : NodePopup.this.owner.getGUI().getGraph().getSelectedCubes()) {
                    if (startStopButton.isSelected()) c.getChainNode().start();
                    else c.getChainNode().stop();
                }
            }
        });

        saveChainButton = new TextButton("save...", xor(modbox.getColor()), modbox.getFont());
        saveChainButton.setNegative(false);
        saveChainButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                NodePopup.this.setVisible(false);
                    // save chain
            }
        });

        copyButton = new TextButton("copy", xor(modbox.getColor()), modbox.getFont());
        copyButton.setNegative(false);
        copyButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                NodePopup.this.setVisible(false);
                String names = "";
                for (NodeCube c : owner.getGUI().getGraph().getSelectedCubes())
                    names += c.getChainNode().getName() + ", ";
                owner.sendShellCommand("copy " + names.substring(0, names.length()-2));
            }
        });

        duplicateButton = new TextButton("duplicate", xor(modbox.getColor()), modbox.getFont());
        duplicateButton.setNegative(false);
        duplicateButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                NodePopup.this.setVisible(false);
                String names = "";
                for (NodeCube c : owner.getGUI().getGraph().getSelectedCubes())
                    names += c.getChainNode().getName() + ", ";
                owner.sendShellCommand("duplicate " + names.substring(0, names.length()-2));
            }
        });

        debugButton = new TextButton("debug: on", xor(modbox.getColor()), modbox.getFont());
        debugButton.setNegative(false);
        debugButton.setToggleButton(true);
        debugButton.setUnselectedText("debug: off");
        debugButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                setVisible(false);
                for (NodeCube c : owner.getGUI().getGraph().getSelectedCubes()) {
                    c.getChainNode().setDebugFlag(debugButton.isSelected());
                }
            }
        });

        infoButton = new TextButton("info: on", xor(modbox.getColor()), modbox.getFont());
        infoButton.setNegative(false);
        infoButton.setToggleButton(true);
        infoButton.setUnselectedText("info: off");
        infoButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent ae) {
                setVisible(false);
                for (NodeCube c : owner.getGUI().getGraph().getSelectedCubes()) {
                    c.getChainNode().setDebugFlag(infoButton.isSelected());
                }
            }
        });

        msgArea.setMargin(new Insets(1, 2, 1, 2));
        msgArea.setLineWrap(true);
        msgArea.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    NodePopup.this.setVisible(false);
                    NodePopup.this.sendToNode();
                }
            }
        });
        
        GridBagConstraints c = new GridBagConstraints();

        JPanel titlePanel = new JPanel();
        titlePanel.setOpaque(true);
        titlePanel.setBackground(Color.BLACK);
        titlePanel.setLayout(new GridBagLayout());

        c.gridy = 0; c.fill = GridBagConstraints.BOTH; c.weightx = 1.0; c.gridwidth = 1;
        classLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        titlePanel.add(classLabel, c);

        c.gridy = 1; c.insets.bottom = 4; c.gridwidth = 1;
        nameField.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        titlePanel.add(nameField, c);

        c.gridy = 0; c.gridx = 1; c.gridheight = 2; c.weightx = 0; c.fill = GridBagConstraints.HORIZONTAL;
        titlePanel.add(disconnectButton, c);

        c = new GridBagConstraints();
        c.gridy = 0; c.gridx = 0; c.gridwidth = 2; c.fill = GridBagConstraints.BOTH;
        add(titlePanel, c);
        c.gridy = 2; c.insets.bottom = 2; c.gridwidth = 2; c.gridheight = 1;
        sendLabel.setAlignmentX(JLabel.CENTER_ALIGNMENT);
        sendLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        add(sendLabel, c);

        c.gridy = 3; c.insets.bottom = 1; c.gridwidth = 2;
        add(msgArea, c);

        c = new GridBagConstraints();
        c.fill = GridBagConstraints.BOTH; c.gridwidth = 1; c.weightx = 1; c.weighty = 1;
        c.insets.bottom = 1; c.insets.left = 1; c.insets.right = 0; c.insets.top = 0;

        c.insets.right = 0;
        c.gridx = 0; c.gridy = 4;
        startStopButton.setMargin(new Insets(2,1,2,1));
        add(startStopButton, c);

        c.insets.right = 1;
        c.gridx = 1; c.gridy = 4;
        copyButton.setMargin(new Insets(2,1,2,1));
        add(copyButton, c);

        c.insets.right = 0;
        c.gridx = 0; c.gridy = 5;
        duplicateButton.setMargin(new Insets(2,1,2,1));
        add(duplicateButton, c);

        c.insets.right = 1;
        c.gridx = 1; c.gridy = 5;
        removeButton.setMargin(new Insets(2,1,2,1));
        add(removeButton, c);

        c.insets.right = 0;
        c.gridx = 0; c.gridy = 6;
        debugButton.setMargin(new Insets(2,1,2,1));
        add(debugButton, c);

        c.insets.right = 1;
        c.gridx = 1; c.gridy = 6;
        infoButton.setMargin(new Insets(2,1,2,1));
        add(infoButton, c);

        c.insets.right = 0;
        c.gridx = 0; c.gridy = 7;
        saveChainButton.setMargin(new Insets(2,1,2,1));
        add(saveChainButton, c);

        pack();
    }

    private Color xor(Color c) {
        return new Color(255-c.getRed(), 255-c.getGreen(), 255-c.getBlue());
    }

    @Override
    public void setColor(Color c) {
        Color xor = ColorParser.xor(c);
        super.setColor(xor);
        this.setBackground(ColorParser.lighterBy(xor, 0.2f));
        disconnectButton.setColor(xor);
        removeButton.setColor(xor);
        saveChainButton.setColor(xor);
        startStopButton.setColor(xor);
        copyButton.setColor(xor);
        duplicateButton.setColor(xor);
        debugButton.setColor(xor);
        infoButton.setColor(xor);
        sendLabel.setForeground(xor);
        msgArea.setForeground(Color.black);
        msgArea.setBackground(xor(c));
        msgArea.setCaretColor(xor(c).brighter());
        msgArea.setSelectionColor(xor(c).darker());
        msgArea.setBorder(BorderFactory.createEmptyBorder(1,1,0,1));
        nameField.setForeground(c);
        nameField.setCaretColor(c);
        classLabel.setForeground(c);
    }

    @Override
    public void setFont(Font f) {
        classLabel.setFont(f.deriveFont(Font.BOLD, (float)(f.getSize()*1.1*1.1)));
        nameField.setFont(f.deriveFont((float)(f.getSize()*1.1)));
        disconnectButton.setFont(f.deriveFont(Font.PLAIN, (float)Math.round(f.getSize()*0.9f)));
        removeButton.setFont(f);
        saveChainButton.setFont(f);
        copyButton.setFont(f);
        duplicateButton.setFont(f);
        startStopButton.setFont(f);
        debugButton.setFont(f);
        infoButton.setFont(f);
        sendLabel.setFont(f.deriveFont(Font.PLAIN, (float)Math.round(f.getSize()*0.9f)));
        msgArea.setFont(new Font("Courier", f.getStyle(), f.getSize()));
    }

    public abstract void updateSelection(List<NodeCube> selection);

    private void sendToNode() {
        if (!owner.getActualBoxChain().isRunning()) {
            owner.log("Can't send message while chain is closed.", MSG.ERROR);
            return;
        }

        msgArea.setText(msgArea.getText().trim());
        try {
            Variable message = Variable.parseVariable("modboxMsg", null, msgArea.getText(), false);
            if (message.isEvaluateAtHome()) message = message.evaluate(owner.getActualBoxChain());

            for (NodeCube c : owner.getGUI().getGraph().getSelectedCubes())
                c.getChainNode().send(message, -1, Channel.CHAIN);
        } catch (IllegalArgumentException ie) {
            owner.log("While creating variable: " + ie, MSG.ERROR);
        }
    }
}

class SingleNodePopup extends NodePopup {
    ChainNode node;

    public SingleNodePopup(Modbox owner) {
        super(owner);
        nameField.addKeyListener(new KeyAdapter(){

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode()==KeyEvent.VK_ENTER) {
                    SingleNodePopup.this.setVisible(false);
                    SingleNodePopup.this.renameNode();
                }
            }
        });
    }

    public void updateSelection(List<NodeCube> selection) {
        //if (selection.isEmpty()) return;

        node = selection.get(0).getChainNode();
        classLabel.setText(node.getNodeClassName());
        nameField.setText(node.getName());
        startStopButton.setSelected(node.isRunning());
        debugButton.setSelected(node.getDebugFlag());
        infoButton.setSelected(node.getInfoFlag());
        if (node!=null && (node instanceof Chain)) saveChainButton.setVisible(true);
        else saveChainButton.setVisible(false);
        msgArea.requestFocusInWindow();
        System.out.println("nodeoutputs=" + node.getOutputs().size() + " inputs=" + node.getInputs().size());
        if (node.getOutputs().size() + node.getInputs().size()==0) disconnectButton.setVisible(false);
        else disconnectButton.setVisible(true);
        pack();
    }

    private void renameNode() {
        if (!nameField.getText().equals(node.getName())) {
            try {
                owner.getActualBoxChain().renameChild(node, nameField.getText());
            } catch (IllegalArgumentException ie) {
                owner.log("While renaming node: " + ie, MSG.ERROR);
            }
        }
    }

}

class MultiNodePopup extends NodePopup {
    public MultiNodePopup(Modbox owner) {
        super(owner);
        nameField.setEditable(false);
    }

    @Override
    public void updateSelection(List<NodeCube> selection) {
        boolean anyRunning = false;
        boolean anyDebug = false, anyInfo = false;
        classLabel.setText("Multiple");

        String names = "";
        for (NodeCube c : selection) {
            names += c.getChainNode().getName() + ", ";
            if (c.getChainNode().isRunning()) anyRunning = true;
            if (c.getChainNode().getDebugFlag()) anyDebug = true;
            if (c.getChainNode().getInfoFlag()) anyInfo = true;
        }
        if (names.length()>2)
            names = names.substring(0, names.length()-2);

        nameField.setToolTipText(names);
        if (names.length()>25) names = names.substring(0, 25)+"...";
        nameField.setText(names);

        startStopButton.setSelected(anyRunning);
        debugButton.setSelected(anyDebug);
        infoButton.setSelected(anyInfo);

        disconnectButton.setVisible(false);
        saveChainButton.setVisible(false);
        pack();
    }
}